"""
作者：swh
日期：2019.1.18
描述：绘制二维的点线图
类COLOR：定义常用颜色
类STYLE：定义常见点的形状
类DrawTwoDim：定义绘图的方法
"""
import matplotlib.pyplot as plt
from typing import List, Tuple
import ColorAndStyle


class DrawTwoDim:
    def __init__(self, nodes: List[Tuple[int, int]], name: str = None, is_title_dis: bool = True):
        self._nodes = nodes
        self._xs = [node[0] for node in self._nodes]
        self._ys = [node[1] for node in self._nodes]
        self._figure = plt.figure(1)
        self._ax = self._figure.gca()
        self._size_inch = 50
        self._adjust_area()
        self._title_size = 30
        self._text_size = 25
        self._axis_size = 30
        if is_title_dis:
            plt.title(name, fontsize=self._title_size)

    def _adjust_area(self):
        # leave some space around the visible area
        left = right = self._nodes[0][0]
        up = down = self._nodes[0][1]
        for node in self._nodes[1:]:
            if node[0] > right:
                right = node[0]
            elif node[0] < left:
                left = node[0]
            if node[1] > up:
                up = node[1]
            elif node[1] < down:
                down = node[1]
        self._ax.set_xlim((left - 0.5) * 1.1, (right + 0.5) * 1.1)
        self._ax.set_ylim((down - 0.5) * 1.1, (up + 0.5) * 1.1)
        plt.gcf().set_size_inches(self._size_inch, self._size_inch)

    def draw_all_nodes(self,
                       style: ColorAndStyle.COLOR.GREEN + ColorAndStyle.STYLE.square
                       = ColorAndStyle.COLOR.GREEN + ColorAndStyle.STYLE.square):
        for i in range(len(self._nodes)):
            x, y = self._nodes[i]
            plt.plot(x, y, style, label=str(i))

    def draw_nodes(self, nodes_id: List[int], nodes_infor: List[str] = None,
                   color=ColorAndStyle.COLOR.GREEN, marker=ColorAndStyle.STYLE.square,
                   delta_x: int = 0, delta_y: int = 0, label: str = None, marksize=10):
        for i in range(len(nodes_id)):
            _id = nodes_id[i]
            x, y = self._nodes[_id][0], self._nodes[_id][1]
            if i == 0 and label:
                plt.plot(x, y, color=color, marker=marker, ms=marksize, label=label)
            else:
                plt.plot(x, y, color=color, marker=marker, ms=marksize)
            if nodes_infor:
                self.addComment(x, y, x, y, nodes_infor[i], delta_x, delta_y)

    def addComment(self, x1, y1, x2, y2, infor, delta_x=0, delta_y=0):
        """
        在点的正上方或者线的中点上方添加注释
        :param delta_y: 相对于默认位置的纵座标偏倚量
        :param delta_x: 相对于默认位置的横座标偏倚量
        :param x1: 点1横座标
        :param y1: 点1纵座标
        :param x2: 点2横座标
        :param y2: 点2纵座标
        :param infor: 注释信息
        :return: 无
        """
        middle_x = (x1 + x2) / 2
        middle_y = (y1 + y2) / 2
        plt.annotate(infor, xy=(middle_x, middle_y),
                     xytext=(middle_x + delta_x, middle_y + delta_y), size=self._text_size)

    def draw_lines_with_arrow(self, arcs, arcs_infor=None, color=ColorAndStyle.COLOR.RED,
                              label=None, delta_x=0, delta_y=0):
        """
        根据边中点的编号画带箭头的直线以及显示线的注释
        :param label: 线的图例
        :param arcs: 二元元组列表，表示线的两个端点的点的编号
        :param arcs_infor: 字符串列表，与arcs一一对应，表示线的注释
        :param color: 线的颜色
        :return: 无
        """
        for i in range(len(arcs)):
            node1 = self._nodes[arcs[i][0]]
            node2 = self._nodes[arcs[i][1]]
            u = node2[0] - node1[0]
            v = node2[1] - node1[1]
            if i == 0 and label:
                self._ax.quiver(node1[0], node1[1], u, v,
                                color=color, label=label,
                                angles='xy', scale_units='xy', scale=1)
            else:
                self._ax.quiver(node1[0], node1[1], u, v,
                                color=color, angles='xy', scale_units='xy', scale=1)
            if arcs_infor:
                self.addComment(node1[0], node1[1], node2[0], node2[1],
                                arcs_infor[i], delta_x, delta_y)

    def draw_lines(self, arcs, arcs_infor=None, color=ColorAndStyle.COLOR.RED, label=''):
        """
        根据边中点的编号画无箭头的直线以及显示线的注释
        :param label: 线的图例
        :param arcs: 二元元组列表，表示线的两个端点的点的编号
        :param arcs_infor: 字符串列表，与arcs一一对应，表示线的注释
        :param color: 线的颜色
        :return: 无
        """
        for i in range(len(arcs)):
            xs = [self._xs[arcs[i][0]], self._xs[arcs[i][1]]]
            ys = [self._ys[arcs[i][0]], self._ys[arcs[i][1]]]
            if i == 0:
                self._ax.plot(xs, ys, c=color, label=label)
            else:
                self._ax.plot(xs, ys, c=color)
            if arcs_infor:
                self.addComment(xs[0], ys[0], xs[1], ys[1], arcs_infor[i])

    def show(self, filename='hello'):
        box = self._ax.get_position()
        self._ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
        # 调整图示位置
        self._ax.legend(loc='right', bbox_to_anchor=(1.35, 0.5), ncol=1)
        plt.tick_params(labelsize=self._axis_size)
        plt.savefig(filename+'.png', dpi=100)
        plt.show()


__all__ = ['DrawTwoDim']